package it.unisannio.lesim.servlet;

import it.unisannio.lesim.fsm.FSM;
import it.unisannio.lesim.fsm.State;
import it.unisannio.lesim.parser.ErrorHandlerImpl;
import it.unisannio.lesim.parser.ParserXML;
import java.io.*;

import java.util.ArrayList;
import java.util.Hashtable;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;

/**
 *
 * @author Marco Calisti
 * @author Antonio Cuomo
 * @author Rocco Mazzeo
 * @author Francesco Pacilio
 * 
 */

public class FsmServlet extends HttpServlet {
   
    /** 
    * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
    * @param request servlet request
    * @param response servlet response
    */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        String req = request.getRequestURI();
        if (req.equals("/AnalizzatoreSip/AddFsm")) {
            addFsm(request, response);
        } else if (req.equals("/AnalizzatoreSip/SaveFSM")) {
            saveFSM(request, response);
        } else if (req.equals("/AnalizzatoreSip/DeleteFSM")) {
            deleteFSM(request, response);
        } else if (req.equals("/AnalizzatoreSip/AddState")) {
            addState(request, response);
        } else if (req.equals("/AnalizzatoreSip/AddTransition")) {
            addTransition(request, response);
        } else if (req.equals("/AnalizzatoreSip/AddComplete")) {
            addComplete(request, response);
        } else if (req.equals("/AnalizzatoreSip/FinalStep")) {
            finalStep(request, response);
        } else if (req.equals("/AnalizzatoreSip/Cancel")) {
            cancel(request, response);
        }
    }
    
    private void addFsm(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String nome = request.getParameter("nome");
        String descrizione = request.getParameter("descrizione");
        ParserXML parser = new ParserXML(this.getServletContext().getRealPath("FSM.xml"));
        ArrayList fsms = parser.readFSMS();
        boolean nomePresente=false;
        for(int i=0;i<fsms.size();i++) {
            FSM f = (FSM)fsms.get(i);
            if(f.getName().equals(nome)) {
                nomePresente=true;
            }
            if(nomePresente) break;
        }
        if(nome.length()==0 || descrizione.length()==0) {
            request.setAttribute("MSG", "I campi non possono essere vuoti");
            gotoPage("/def_fsm.jsp",request,response);
        }
        else if(nomePresente) {
            request.setAttribute("MSG", "Il nome della FSM e' gia' presente");
            gotoPage("/def_fsm.jsp",request,response);
        }
        else {
            FSM fsm = new FSM(nome,descrizione);
            HttpSession session = request.getSession();
            session.setAttribute("fsm", fsm);
            gotoPage("/def_state.jsp", request, response);
        } 
    }

    private void addState(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String nome = request.getParameter("nome");
        String descrizione = request.getParameter("descrizione");
        if(nome.length()==0 || descrizione.length()==0) {
            request.setAttribute("MSG", "I campi non possono essere vuoti");
            gotoPage("/def_state.jsp",request,response);
        }
        else {
        State stato = new State(nome,descrizione);
        String tipo = request.getParameter("tipo");
        String error= request.getParameter("checkbox");
        HttpSession session = request.getSession();
        FSM fsm = (FSM) session.getAttribute("fsm");
        session.removeAttribute("fsm");
        if(tipo.equals("first state")) session.setAttribute("statoIniziale",nome);
        if(tipo.equals("final state")) stato.setIsFinal(true);
        else stato.setIsFinal(false);
        if(error==null) stato.setIsError(false);
        else stato.setIsError(true);
        fsm.addState(stato);
        request.setAttribute("MSG", "Stato inserito correttamente");
        session.setAttribute("fsm", fsm);
        gotoPage("/def_state.jsp", request, response);
        }
    }
    
    private void addTransition(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         String statoDa = request.getParameter("select");
         String statoA = request.getParameter("select2");
         String condizione = request.getParameter("condizione");
         String azione = request.getParameter("azione");
         HttpSession session = request.getSession();
         FSM fsm = (FSM) session.getAttribute("fsm");
         session.removeAttribute("fsm");
         ((State)(((Hashtable)(fsm.getHashStates())).get(statoDa))).addTransition(fsm, statoA, condizione, azione);
         int curr = (Integer)session.getAttribute("currentTrans");
         session.setAttribute("currentTrans", ++curr);
         session.setAttribute("fsm", fsm);
         request.setAttribute("MSG", "Transizione inserita correttamente");
         gotoPage("/def_trans.jsp", request, response);    
    }
        
    private void addComplete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         HttpSession session = request.getSession();
         FSM fsm = (FSM) session.getAttribute("fsm");
         String statoIniziale = (String)session.getAttribute("statoIniziale");
         
         fsm.setFirstState(statoIniziale);
         removeAttribute(request,response);
         ParserXML parser = new ParserXML(this.getServletContext().getRealPath("FSM.xml"));
         ArrayList fsms = parser.readFSMS();
         fsms.add(fsm);
         parser.writeFSMS(fsms, this.getServletContext().getRealPath("FSM_temp.xml"), this.getServletContext().getRealPath("FSM.xml"));
         request.setAttribute("Messaggio", "FSM inserita correttamente.");
         gotoPage("/deleteFSM.jsp", request, response);
    }
    
    private void finalStep(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
        FSM fsm = (FSM) session.getAttribute("fsm");
        Hashtable h = (Hashtable) fsm.getHashStates();
        String statoIniziale = (String)session.getAttribute("statoIniziale");
        if(statoIniziale==null) {
            request.setAttribute("MSG", "Per procedere bisogna aver settato uno stato iniziale");
            gotoPage("/def_state.jsp", request, response);
        }
        else {
            session.setAttribute("MinTrans", (h.size()-1));
            session.setAttribute("currentTrans", 0);
            gotoPage("/def_trans.jsp", request, response);
        }
    }

    private void deleteFSM(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            String[] NameFSM = request.getParameterValues("fsm");

            if (NameFSM != null) {

                HttpSession session = request.getSession();
                ArrayList fsms = (ArrayList) session.getAttribute("FSM_Temp");
                session.removeAttribute("FSM_Temp");

                for (int i = 0; i < NameFSM.length; i++) {

                    for (int j = 0; j < fsms.size(); j++) {
                        FSM temp = (FSM) fsms.get(j);
                        if (temp.getName().equalsIgnoreCase(NameFSM[i])) {
                            fsms.remove(temp);
                            break;
                        }
                    }
                }

                //fsms sono gli oggetti FSM attivi
                ParserXML parser = new ParserXML(this.getServletContext().getRealPath("FSM.xml"));
                parser.writeFSMS(fsms, this.getServletContext().getRealPath("FSM_temp.xml"), this.getServletContext().getRealPath("FSM.xml"));
                request.setAttribute("Messaggio", "L'operazione e' avvenuta con successo");
                gotoPage("/deleteFSM.jsp", request, response);
            } else {
                HttpSession session = request.getSession();
                ParserXML parser = new ParserXML(this.getServletContext().getRealPath("FSM.xml"));
                parser.writeFSMS((ArrayList) session.getAttribute("FSM_Temp"), this.getServletContext().getRealPath("FSM_temp.xml"), this.getServletContext().getRealPath("FSM.xml"));
                request.setAttribute("Messaggio", "Si prega di selezionare almeno una FSM");
                request.setAttribute("FSM", (ArrayList) session.getAttribute("FSM_Temp"));
                gotoPage("/deleteFSM.jsp", request, response);
            }
        } catch (Exception e) {
            request.setAttribute("Messaggio", "Si e' verificato un errore si prega di ripetere l'operazione");
            gotoPage("/index.jsp", request, response);
        }
    }

    private void saveFSM(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            String fsm = request.getParameter("textarea").replace("&&", "&amp;&amp;");
            fsm=fsm.replace("time<", "time&lt;");
            
            fsm=fsm.replaceAll("]<(?=[^/])", "]&lt;");
            
            File f = new File(this.getServletContext().getRealPath("FSM_temp.xml"));
            PrintStream ps = new PrintStream(new FileOutputStream(f));
            ps.print(fsm);

            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setValidating(true);
            DocumentBuilder builder = factory.newDocumentBuilder();

            ErrorHandlerImpl eh = new ErrorHandlerImpl();

            builder.setErrorHandler(eh);
            
            Document xmlDocument = builder.parse(new FileInputStream(this.getServletContext().getRealPath("FSM_temp.xml")));
            DOMSource source = new DOMSource(xmlDocument);
            StreamResult result = new StreamResult(System.out);
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer transformer = tf.newTransformer();
            transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, this.getServletContext().getRealPath("FSM.dtd"));
            transformer.transform(source, result);

            if (eh.isError()) {
                request.setAttribute("Messaggio", eh.getErrore());
                gotoPage("/fsm.jsp", request, response);
            } else {
                File ff = new File(this.getServletContext().getRealPath("FSM.xml"));
                PrintStream pss = new PrintStream(new FileOutputStream(ff));
                pss.print(fsm);

                request.setAttribute("Messaggio", "L'aggiornamento del file e' avvenuto con successo");
                gotoPage("/fsm.jsp", request, response);
            }

        } catch (Exception e) {
            request.setAttribute("Messaggio", "Si e' verificato un errore si prega di ripetere l'operazione");
            gotoPage("/index.jsp", request, response);
        }
    }
    
    private void cancel(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        removeAttribute(request, response);
        gotoPage("/def_fsm.jsp", request, response);
    }

    private void removeAttribute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
        session.removeAttribute("fsm");
        session.removeAttribute("statoIniziale");
        session.removeAttribute("MinTrans");
        session.removeAttribute("currentTrans");
    }
    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /** 
     * Handles the HTTP <code>GET</code> method.
     * @param request servlet request
     * @param response servlet response
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        processRequest(request, response);
    }

    /** 
     * Handles the HTTP <code>POST</code> method.
     * @param request servlet request
     * @param response servlet response
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        processRequest(request, response);
    }

    /** 
     * Returns a short description of the servlet.
     */
    public String getServletInfo() {
        return "Short description";
    }

    private void gotoPage(String url, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        RequestDispatcher dispacher = getServletContext().getRequestDispatcher(url);
        dispacher.forward(request, response);
    }
    
}
